#include <mathematics/Vector2.h>

namespace ne
{
    const Vector2 Vector2::ZERO(0.0f);
    const Vector2 Vector2::ONE(1.0f);
    const Vector2 Vector2::UNIT_X(1.0f, 0.0f);
    const Vector2 Vector2::UNIT_Y(0.0f, 1.0f);
    const Vector2 Vector2::NEGATIVE_ONE(-1.0f);
    const Vector2 Vector2::NEGATIVE_UNIT_X(-1.0f, 0.0f);
    const Vector2 Vector2::NEGATIVE_UNIT_Y(0.0f, -1.0f);

    Vector2 operator + (const real vl, const Vector2 &vr)
    {
        return Vector2(vl + vr.x, vl + vr.y);
    }

    Vector2 operator - (const real vl, const Vector2 &vr)
    {
        return Vector2(vl - vr.x, vl - vr.y);
    }

    Vector2 operator * (const real vl, const Vector2 &vr)
    {
        return Vector2(vl * vr.x, vl * vr.y);
    }

    Vector2 operator / (const real vl, const Vector2 &vr)
    {
        assert((vr.x != 0.0f) && (vr.y != 0.0f));
        return Vector2(vl / vr.x, vl / vr.y);
    }

    std::ostream& operator << (std::ostream &o, const Vector2 &v)
    {
        o << "Vector2(x=" << v.x <<
                   ", y=" << v.y << ")";
        return o;
    }

    bool Vector2::Equal(const Vector2 &vS, const Vector2 &vD, const real tolerance)
    {
        return (Math::Equal(vS.x, vD.x, tolerance) &&
                Math::Equal(vS.y, vD.y, tolerance));
    }

    Vector2 Vector2::Mid(const Vector2 &vS, const Vector2 &vD)
    {
        return (vS + vD) * 0.5f;
    }

    Vector2 Vector2::Lerp(const Vector2 &vS, const Vector2 &vD, const real u)
    {
        return vS + (vD - vS) * u;
    }

    Vector2 Vector2::Bezier(const Vector2 &vS, const Vector2 &vA, const Vector2 &vB, const Vector2 &vD, const real u)
    {
        Vector2 a = vD - vS + vA * 3.0f - vB * 3.0f;
        Vector2 b = vS * 3.0f - vA * 6.0f + vB * 3.0f;
        Vector2 c = vA * 3.0f - vS * 3.0f;
        real uu = u * u;
        real uuu = uu * u;
        return (a * uuu) + (b * uu) + (c * u) + vS;
    }
}
